﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using HenIT.Windows.Controls;
using System.IO;
using System.Diagnostics;

namespace HenIT.CAGCompare
{
    public partial class CompareGAC : Form
    {
        private HenIT.Windows.Controls.ListViewColumnSorter lvwSorter;
        private int differenceCount = 0;
        private string lastHighLightSearch = "";
        public CompareGAC()
        {
            InitializeComponent();
        }

        #region Form events
        private void CompareMatrix_Load(object sender, EventArgs e)
        {
            this.Text = "Global Assembly Cache Comparer - " + System.Windows.Forms.Application.ProductVersion.ToString();
            if (Properties.Settings.Default.NewVersion)
            {
                Properties.Settings.Default.Upgrade();
                Properties.Settings.Default.NewVersion = false;
                Properties.Settings.Default.Save();
            }
            if (Properties.Settings.Default.PreviousMachineList == null)
                Properties.Settings.Default.PreviousMachineList = new System.Collections.Specialized.StringCollection();

            if (Properties.Settings.Default.CompareMatrixSize != new Size(0, 0))
            {
                this.Location = Properties.Settings.Default.CompareMatrixLocation;
                this.Size = Properties.Settings.Default.CompareMatrixSize;
            }
            if (Properties.Settings.Default.AssemblyColumnSize > 0 && lstGAC.Columns.Count > 0)
            {
                lstGAC.Columns[0].Width = Properties.Settings.Default.AssemblyColumnSize;
            }

            lvwSorter = new ListViewColumnSorter(lstGAC, true, SortColumnType.StringType, SortColumnType.StringType, SortColumnType.StringType);
            if (Properties.Settings.Default.PreviousMachines != null)
            {
                txtMachines.Text = Properties.Settings.Default.PreviousMachines;
            }
            txtFilter.Text = Properties.Settings.Default.PreviousFilter;
            autoShowDifferencesToolStripMenuItem.Checked = Properties.Settings.Default.AutoHighlightDiff;
        }
        private void CompareMatrix_FormClosing(object sender, FormClosingEventArgs e)
        {
            if (WindowState == FormWindowState.Normal)
            {
                Properties.Settings.Default.CompareMatrixLocation = this.Location;
                Properties.Settings.Default.CompareMatrixSize = this.Size;
            }
            Properties.Settings.Default.AutoHighlightDiff = autoShowDifferencesToolStripMenuItem.Checked;
            Properties.Settings.Default.PreviousFilter = txtFilter.Text;
            Properties.Settings.Default.AssemblyColumnSize = lstGAC.Columns[0].Width;
            Properties.Settings.Default.PreviousMachines = txtMachines.Text;
            Properties.Settings.Default.Save();
        } 
        #endregion

        #region Button events
        private void cmdCompare_Click(object sender, EventArgs e)
        {
            bool isAllSame;
            try
            {
                if (txtMachines.Text.Length > 0)
                {
                    viewAsHTMLReportToolStripMenuItem.Enabled = false;
                    exportAsXMLToolStripMenuItem.Enabled = false;
                    differenceCount = 0;
                    lvwSorter.Disable();
                    lstGAC.Items.Clear();

                    System.Windows.Forms.Application.DoEvents();
                    Cursor.Current = Cursors.WaitCursor;

                    //Processing machine names
                    string[] machines = txtMachines.Text.Split(',');
                    GACMatrix gacMatrix = new GACMatrix();
                    gacMatrix.Machines = new List<string>();
                    foreach (string machine in machines)
                    {
                        if (NetTools.IsValidMachineName(machine.Trim()))
                            gacMatrix.Machines.Add(machine.Trim().ToUpper());
                    }

                    //loading GAC data
                    for (int i = 0; i < gacMatrix.Machines.Count; i++)
                    {
                        GACList gacList = new GACList();
                        gacList.LoadList(gacMatrix.Machines[i], txtFilter.Text + "*");
                        foreach (GACEntry ge in gacList.Assemblies)
                        {
                            GACMatrixEntry gacMatrixEntry;
                            if (chkCompareFileSize.Checked)
                                gacMatrixEntry = new GACMatrixEntry(
                                     ge.AssemblyName,
                                     ge.AssemblyVersion.ToString(),
                                     ge.Culture,
                                     ge.PublicKeyToken,
                                     ge.FileSize,
                                     ge.GacType);
                            else
                                gacMatrixEntry = new GACMatrixEntry(
                                   ge.AssemblyName,
                                   ge.AssemblyVersion.ToString(),
                                   ge.Culture,
                                   ge.PublicKeyToken,
                                   ge.GacType);
                            gacMatrixEntry.EntryPath = ge.AssemblyPath[0].Substring(3 + gacMatrix.Machines[i].Length);
                            gacMatrixEntry.Machines = new List<string>();
                            gacMatrixEntry.Machines.Add(gacMatrix.Machines[i]);

                            bool foundexisting = false;
                            foreach (GACMatrixEntry gacMatrixEntryExisting in gacMatrix.gacMatrixEntries)
                            {
                                if (gacMatrixEntryExisting.GACEntryName == gacMatrixEntry.GACEntryName)
                                {
                                    gacMatrixEntryExisting.Machines.Add(gacMatrix.Machines[i]);
                                    foundexisting = true;
                                    break;
                                }
                            }
                            if (!foundexisting)
                            {
                                gacMatrix.gacMatrixEntries.Add(gacMatrixEntry);
                            }
                        }
                    }
                    //Clear old machine columns
                    for (int i = lstGAC.Columns.Count - 1; i > 0; i--)
                    {
                        lstGAC.Columns.Remove(lstGAC.Columns[i]);
                    }
                    //Add new machine columns
                    foreach (string machine in gacMatrix.Machines)
                    {
                        lstGAC.Columns.Add(machine.Trim(), 100);
                    }
                    //Load rows to listview
                    gacMatrix.gacMatrixEntries.Sort();
                    foreach (GACMatrixEntry gacMatrixEntry in gacMatrix.gacMatrixEntries)
                    {
                        isAllSame = true;
                        ListViewItem lvi = new ListViewItem(gacMatrixEntry.GACEntryName);
                        for (int i = 1; i < lstGAC.Columns.Count; i++)
                        {
                            string sameX = gacMatrixEntry.Machines.Contains(lstGAC.Columns[i].Text) ? "X" : " ";
                            lvi.SubItems.Add(sameX);
                            if (sameX == " ")
                                isAllSame = false;
                        }
                        lvi.Tag = gacMatrixEntry;
                        lstGAC.Items.Add(lvi);
                        if (!isAllSame)
                            differenceCount++;
                    }
                    lvwSorter.Enable();
                    lstGAC.Sorting = SortOrder.Ascending;
                    lstGAC.Sort();
                    Cursor.Current = Cursors.Default;
                    toolStripStatusLabelItemCount.Text = lstGAC.Items.Count.ToString() + " entries found," +
                        differenceCount.ToString() + " differences";
                    viewAsHTMLReportToolStripMenuItem.Enabled = true;
                    exportAsXMLToolStripMenuItem.Enabled = true;
                    if (autoShowDifferencesToolStripMenuItem.Checked)
                    {
                        highlightDifferencesToolStripMenuItem_Click(null, null);
                        highlightSimilarToolStripMenuItem_Click(null, null);
                    }
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.ToString(), "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }
        private void cmdSelectMachines_Click(object sender, EventArgs e)
        {
            EditMachineNames editMachineNames = new EditMachineNames();
            string[] machines = txtMachines.Text.Split(',');
            foreach (string machineName in machines)
            {
                if (machineName.Trim().Length > 0)
                    editMachineNames.AddSelectedMachine(machineName.Trim());
            }
            if (editMachineNames.ShowDialog() == DialogResult.OK)
            {
                txtMachines.Text = "";
                foreach (string machineName in editMachineNames.SelectedMachines)
                {
                    txtMachines.Text += machineName + ",";
                }
                txtMachines.Text = txtMachines.Text.Trim(',');
                cmdCompare.Enabled = true;
            }
        }
        #endregion

        #region ListView events
        private void lstGAC_SelectedIndexChanged(object sender, EventArgs e)
        {
            toolStripStatusLabelSelectedItems.Text = lstGAC.SelectedItems.Count.ToString() + " item(s) selected";
            exportAssemblysetToToolStripMenuItem.Enabled = lstGAC.SelectedItems.Count > 0;
            exploreAssemblysetToolStripMenuItem.Enabled = lstGAC.SelectedItems.Count > 0;
        }
        private void lstGAC_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.KeyCode == Keys.A && e.Control)
            {
                foreach (ListViewItem lvi in lstGAC.Items)
                {
                    lvi.Selected = true;
                }
            }
            else if (e.KeyCode == Keys.Space)
            {
                foreach (ListViewItem lvi in lstGAC.SelectedItems)
                {
                    if (lvi.BackColor == Color.LightBlue)
                        lvi.BackColor = SystemColors.Window;
                    else
                        lvi.BackColor = Color.LightBlue;
                }
            }
        }
        #endregion

        #region TextBox events
        private void txtMachines_TextChanged(object sender, EventArgs e)
        {
            cmdCompare.Enabled = (txtMachines.Text.Length > 0);
        }
        #endregion

        #region Context menu events
        private void viewAsHTMLReportToolStripMenuItem_Click(object sender, EventArgs e)
        {
            DataTable table = new DataTable();
            try
            {
                Cursor.Current = Cursors.WaitCursor;
                
                int[] totals = new int[lstGAC.Columns.Count-1];
                string[] values = new string[lstGAC.Columns.Count + 1];

                foreach (ColumnHeader colHead in lstGAC.Columns)
                {
                    table.Columns.Add(colHead.Text);
                }
                table.Columns.Add("class");
                foreach (ListViewItem lvi in lstGAC.Items)
                {
                    bool isAllSame = true;
                    for (int i = 0; i < lstGAC.Columns.Count; i++)
                    {
                        values[i] = lvi.SubItems[i].Text;
                        if (i > 0)
                        {
                            totals[i - 1] += (int)(lvi.SubItems[i].Text == "X" ? 1 : 0);
                            if (lvi.SubItems[i].Text != "X")
                                isAllSame = false;
                        }
                    }
                    values[lstGAC.Columns.Count] = isAllSame ? "same" : "diff";
                   
                    table.Rows.Add(values);
                }
                values[0] = "<hr />";
                for (int i = 1; i < lstGAC.Columns.Count; i++)
                {
                    values[i] = "<hr />";
                }
                values[lstGAC.Columns.Count] = "";
                table.Rows.Add(values);

                values[0] = "Totals - " + lstGAC.Items.Count + " item(s), " + 
                    differenceCount.ToString() + " differences";
                for (int i = 1; i < lstGAC.Columns.Count; i++)
                {
                    values[i] = totals[i - 1].ToString();
                }
                values[lstGAC.Columns.Count] = "total";
                table.Rows.Add(values);

                string outPutFile = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "GACReport.htm");
                HTMLReportWriter htmlReportWriter = new HTMLReportWriter();
                htmlReportWriter.AddStyle("h1", "color:maroon");
                htmlReportWriter.AddStyle("table", "border-collapse:collapse;border-spacing:1");
                htmlReportWriter.AddStyle("th", "text-align:left;background-color:WhiteSmoke");
                htmlReportWriter.AddStyle(".diff", "background-color:lightsalmon");
                htmlReportWriter.AddStyle(".total", "background-color:WhiteSmoke");
                htmlReportWriter.AddStyle(".footer", "font-style:italic;background-color:WhiteSmoke");
                htmlReportWriter.AddHeading1("GAC compare report");
                htmlReportWriter.AddHorisontalLine();
                htmlReportWriter.AddTableWithClass(table);
                htmlReportWriter.AddHorisontalLine();
                htmlReportWriter.AddParagraph("Report date: " + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"), "footer");
                if (htmlReportWriter.WriteDocument(outPutFile))
                {
                    Process.Start(outPutFile);
                }
                else
                {
                    MessageBox.Show(htmlReportWriter.LastError, "Error", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.ToString(), "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
            finally
            {
                Cursor.Current = Cursors.Default;
            }
        }
        private void exportAsXMLToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (saveFileDialogXMLExport.ShowDialog() == DialogResult.OK)
            {
                ExportToXML(saveFileDialogXMLExport.FileName);
            }
        }

        private void ExportToXML(string xmlOutputFIle)
        {
            FileStream outstream = File.Create(xmlOutputFIle);
            using (System.Xml.XmlTextWriter wrt = new System.Xml.XmlTextWriter(outstream, Encoding.UTF8))
            {
                wrt.Formatting = System.Xml.Formatting.Indented;
                wrt.Indentation = 5;
                wrt.IndentChar = ' ';
                wrt.WriteStartDocument();
                wrt.WriteStartElement("cagcompare");

                wrt.WriteStartElement("headings");
                foreach (ColumnHeader header in lstGAC.Columns)
                {
                    wrt.WriteStartElement("heading");
                    wrt.WriteString(header.Text);
                    wrt.WriteEndElement();
                }
                wrt.WriteEndElement(); //headings

                wrt.WriteStartElement("data");
                foreach (ListViewItem lvi in lstGAC.Items)
                {
                    wrt.WriteStartElement("row");
                    for (int i = 0; i < lstGAC.Columns.Count; i++)
                    {
                        wrt.WriteStartElement(lstGAC.Columns[i].Text);
                        wrt.WriteString(lvi.SubItems[i].Text);
                        wrt.WriteEndElement();
                    }
                    wrt.WriteEndElement();
                }
                wrt.WriteEndElement(); //data

                wrt.WriteEndElement(); //cagcompare
                wrt.WriteEndDocument();
                wrt.Flush();
            }
            outstream.Close();
        }
        
        private void exportAssemblysetToToolStripMenuItem_Click(object sender, EventArgs e)
        {
            string outputPath = "";
            string machineOutputPath;
            string destinationPath;
            string destinationFile;
            string sourceFile;
            int exportCount = 0;

            StringBuilder errorList = new StringBuilder();
            FolderBrowserDialog fdb = new FolderBrowserDialog();
            if (fdb.ShowDialog() == DialogResult.OK)
            {
                Cursor.Current = Cursors.WaitCursor;
                outputPath = fdb.SelectedPath;
                foreach (ListViewItem lvi in lstGAC.SelectedItems)
                {
                    GACMatrixEntry gacMatrixEntry = (GACMatrixEntry)lvi.Tag;
                    foreach (string machine in gacMatrixEntry.Machines)
                    {
                        try
                        {
                            machineOutputPath = Path.Combine(outputPath, machine);
                            destinationPath = gacMatrixEntry.EntryPath.Substring(gacMatrixEntry.EntryPath.IndexOf("assembly\\") + 9);
                            destinationFile = Path.Combine(machineOutputPath, destinationPath);
                            sourceFile = "\\\\" + machine + "\\" + gacMatrixEntry.EntryPath;
                            if (!Directory.Exists(Path.GetDirectoryName(destinationFile)))
                            {
                                Directory.CreateDirectory(Path.GetDirectoryName(destinationFile));
                            }
                            File.Copy(sourceFile, destinationFile, true);
                            exportCount++;
                        }
                        catch (Exception ex)
                        {
                            errorList.AppendLine("Error exporting " + gacMatrixEntry.EntryPath + ":" + ex.Message);
                        }
                    }
                }
                Cursor.Current = Cursors.Default;
                if (errorList.Length > 0)
                {
                    MessageBox.Show("Export done with errors. " + exportCount.ToString() + " file(s) copied.\r\n" + errorList.ToString(), "Export done with errors", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
                }
                else
                {
                    MessageBox.Show("Export done without errors. " + exportCount.ToString() + " file(s) copied.", "Export", MessageBoxButtons.OK, MessageBoxIcon.Information);
                }
            }
        }
        private void exploreAssemblysetToolStripMenuItem_Click(object sender, EventArgs e)
        {
            List<string> files = new List<string>();

            foreach (ListViewItem lvi in lstGAC.SelectedItems)
            {
                GACMatrixEntry gacMatrixEntry = (GACMatrixEntry)lvi.Tag;
                foreach (string machine in gacMatrixEntry.Machines)
                {
                    try
                    {
                        files.Add(Path.Combine("\\\\", machine, gacMatrixEntry.EntryPath));
                        //sourceFile = "\\\\" + machine + "\\" + gacMatrixEntry.EntryPath;
                        //ExplorePath(Path.Combine("\\\\", machine, gacMatrixEntry.EntryPath));
                    }
                    catch (Exception ex)
                    {
                        MessageBox.Show(ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);                        
                    }
                }
            }
            CompareFiles compareFiles = new CompareFiles();
            compareFiles.SelectedFiles = files;
            compareFiles.Show();
        }
        private void highlightDifferencesToolStripMenuItem_Click(object sender, EventArgs e)
        {
            int columnCount = lstGAC.Columns.Count;
            foreach (ListViewItem lvi in lstGAC.Items)
            {
                bool allSame = true;
                for (int i = 1; i < columnCount; i++)
                {
                    if (lvi.SubItems[i].Text != "X")
                    {
                        allSame = false;
                        break;
                    }
                }
                if (!allSame)
                {
                    lvi.BackColor = Color.LightSalmon;
                }
            }
        }
        private void highlightSimilarToolStripMenuItem_Click(object sender, EventArgs e)
        {
            int columnCount = lstGAC.Columns.Count;
            foreach (ListViewItem lvi in lstGAC.Items)
            {
                bool allSame = true;
                for (int i = 1; i < columnCount; i++)
                {
                    if (lvi.SubItems[i].Text != "X")
                    {
                        allSame = false;
                        break;
                    }
                }
                if (allSame)
                {
                    lvi.BackColor = Color.LightGreen;
                }
            }
        }
        private void highlightSelectedToolStripMenuItem_Click(object sender, EventArgs e)
        {
            foreach (ListViewItem lvi in lstGAC.SelectedItems)
            {
                lvi.BackColor = Color.LightBlue;
            }
        }
        private void highlightBySearchToolStripMenuItem_Click(object sender, EventArgs e)
        {
            InputBox inputBox = new InputBox();
            inputBox.InputString = lastHighLightSearch;
            inputBox.PromptString = "Search for";
            inputBox.Caption = "Highlight by search";
            if (inputBox.ShowDialog() == DialogResult.OK)
            {
                if (inputBox.InputString.Length > 0)
                {
                    foreach (ListViewItem lvi in lstGAC.Items)
                    {
                        if (lvi.Text.ToUpper().Contains(inputBox.InputString.ToUpper()))
                            lvi.BackColor = Color.LightBlue;
                        else
                            lvi.BackColor = SystemColors.Window;
                    }
                }
                lastHighLightSearch = inputBox.InputString;
            }
        }
        private void clearToolStripMenuItem_Click(object sender, EventArgs e)
        {
            foreach (ListViewItem lvi in lstGAC.Items)
            {
                lvi.BackColor = SystemColors.Window;
            }
        } 
        #endregion

        #region Utilities
        private void ExploreDir(string path)
        {
            System.Diagnostics.Process.Start("Explore", path);
            //System.Diagnostics.Process.Start(@"""" + path + @"""");
        }
        private void ExplorePath(string path)
        {
            //System.Diagnostics.Process.Start("Explorer.exe", "/select,\"" + path + "\"");

            ProcessStartInfo startInfo = new ProcessStartInfo("Explorer.exe");
            startInfo.UseShellExecute = false;
            if (File.Exists(path))
                path = Path.GetDirectoryName(path);
            //startInfo.WorkingDirectory = path;
            startInfo.Verb = "select";
            startInfo.Arguments = path;
            //startInfo.Arguments = @"/select,""" + path + "\"";
            Process p = Process.Start(startInfo);
            

            //ShowSelectedInExplorer.OpenNetworkFolder(path);
            //ShowSelectedInExplorer.FileOrFolder(path);
        }
        #endregion



    }
}
